Skip to content

feat(plugins): add @devframes/plugin-git Git dashboard#38

Merged
antfu merged 16 commits into
devframes:mainfrom
antfubot:feat/plugin-git
Jun 24, 2026
Merged

feat(plugins): add @devframes/plugin-git Git dashboard#38
antfu merged 16 commits into
devframes:mainfrom
antfubot:feat/plugin-git

Conversation

@antfubot

Copy link
Copy Markdown
Contributor

What

Adds @devframes/plugin-git (plugins/git/) — the first built-in plugin: a read-only Git dashboard you can drop into any devframe host or run standalone.

It surfaces the workspace repository over type-safe RPC:

  • git:status — branch, upstream ahead/behind, and staged / unstaged / untracked files
  • git:log — paginated commit history
  • git:branches — local branches with SHA, upstream tracking, and tip subject
  • git:diff — per-file added/deleted counts plus a unified patch for a selected file

The UI is a Next.js App Router + shadcn/ui SPA. Every function is a query with snapshot: true, so the same bundle resolves live over WebSocket in dev and from a build-time snapshot for static deploys, and degrades cleanly to an empty isRepo: false state outside a repository.

Usage

import { createGitDevframe } from '@devframes/plugin-git'

Mount it into a host via devframe's adapters, or run it standalone:

npx devframe-git          # live dev server
npx devframe-git build    # static deploy

createGitDevframe({ repoRoot?, basePath?, distDir?, port? }) keeps the mount path adapter-resolved (/ standalone, /__git/ hosted).

Packaging

Publish-ready alongside @devframes/hub: tsdown compiles the node side to dist/ (.mjs + .d.mts), the SPA is built into dist/client/, and the tarball ships bin.mjs + dist/ only. Wired into the workspace (plugins/* glob, turbo, vitest); the tsnapi public-API snapshot is included.

This PR was created with the help of an agent.

@netlify

netlify Bot commented Jun 18, 2026

Copy link
Copy Markdown

Deploy Preview for devfra ready!

Name Link
🔨 Latest commit b7b59c9
🔍 Latest deploy log https://app.netlify.com/projects/devfra/deploys/6a3a35bdfa01d20008939043
😎 Deploy Preview https://deploy-preview-38--devfra.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

antfubot added 16 commits June 23, 2026 07:19
A publishable devframe plugin that surfaces a read-only Git dashboard
(status, log, branches, diff) through type-safe RPC, with a Next.js
App Router + shadcn/ui SPA. Resolves live over WebSocket in dev and from
a build-time snapshot for static deploys; mountable into any host via
createGitDevframe() or runnable standalone with the bundled devframe-git CLI.
Add a combined dev runner that starts the Next.js HMR server and the
devframe RPC/WebSocket backend at once, wiring the client to the backend
via NEXT_PUBLIC_DEVFRAME_WS. Print a ready banner from the CLI so the
headless server no longer looks idle, and keep dev:client / dev:server
for running a single side.
- Light/dark mode following the system preference with a manual toggle
  and a no-flash inline script; theme tokens already shipped in globals.css.
- SourceTree-style commit graph in the log: git:log now returns parent
  hashes (--topo-order) and the client computes lanes and draws colored
  SVG edges/nodes alongside fixed-height commit rows.
- Stage / unstage / commit from the UI via gated git:stage, git:unstage,
  and git:commit actions (createGitDevframe({ write: true }) or --write).
  Status reports canWrite; the UI exposes per-file and bulk controls plus
  a commit box only when write mode is on over a live connection.
Redesign the commit list around a SourceTree/GitLens-style graph: colored
lane lines with hollow ringed nodes, left-aligned branch/tag label pills
(the checked-out branch rendered as a solid current pill), per-row
lane-tinted highlight bars, and a dashed "Work in Progress" row driven by
the working-tree status. Branch/tag/remote/HEAD refs are parsed from the
raw git ref strings.

Also fixes the previously broken Storybook build by wiring the React JSX
plugin needed under Vite 8's rolldown bundler.
…ls with stories

The git:log snapshot baked only page one and served it for every request, so
in a static deploy 'Load more' could never advance and was disabled outright.
Bake the head of history (up to the 200-commit handler ceiling) as the
snapshot instead, reporting hasMore: false since a static bundle has no
further page — the dashboard now shows full history offline and live mode
keeps paginating. Drops the now-unnecessary live-only gate on the button.

Adds Storybook stories for the status, branches, and diff panel views
alongside the existing log stories.
Replace the manual Load more button with an IntersectionObserver sentinel
that streams the next 30-commit page as the list scrolls, and make commit
rows selectable. Selecting a commit opens a details panel in the right
sidebar (subject, refs, author/committer, parents, message, changed files,
and the patch) backed by a new git:show RPC. The RPC bakes per-commit
records for the snapshot window so static builds show details offline.
Give the dashboard an identity tied to the commit graph: the neutral
grayscale primary/ring tokens become a violet accent (light and dark),
surfacing in the logo chip, focus rings, selected commit, and patch hunk
headers. Add a sticky app-shell top bar, slim theme-aware scrollbars for
native overflow regions, and a selection color.

Apply data-presentation rules across the panels: tabular-nums for every
technical value (counts, ahead/behind, SHAs, +/- stats, relative times)
so they stop jittering, and title attributes on truncated subjects, refs,
paths, and branch names so the full value is recoverable on hover. Also
drops an em dash from a status string.
Rework the dashboard into a devtools shell modeled on vite-devtools'
rolldown UI: a fixed-height app that fills the viewport with no page
scroll, flat panels separated by a single 1px border that doubles as a
drag-to-resize handle (left sidebar and the commit-details rail persist
their widths to localStorage), and each panel scrolling inside its own
region.

Drops the rounded card chrome, folds the branch list into the left rail
under its own panel heading, and makes the Status and commit-details
panels fill and scroll like the commit log already does. The patch
renderer gains an inline (non-scrolling) mode so the details rail keeps a
single scroll context. Storybook's decorator now frames stories in a
fixed-height bordered panel to match.
@antfu antfu marked this pull request as ready for review June 24, 2026 02:08
Copilot AI review requested due to automatic review settings June 24, 2026 02:08
@antfu antfu merged commit 3828b2d into devframes:main Jun 24, 2026
12 checks passed

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds @devframes/plugin-git as a new built-in devframe plugin providing a Git dashboard (RPC-backed status/log/branches/diff + optional write actions) with a standalone CLI and a bundled Next.js SPA for hosted/static usage.

Changes:

  • Registers the new plugins/git workspace with build/test wiring (turbo + vitest) and adds required frontend/storybook deps to pnpm catalogs.
  • Implements the Git RPC surface (status/log/branches/diff/show + optional stage/unstage/commit) and a CLI entry for standalone running/building.
  • Adds a Next.js App Router + shadcn/ui client (components, views, Storybook stories) and corresponding build/dev scripts.

Reviewed changes

Copilot reviewed 72 out of 75 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
vitest.config.ts Includes plugins/git in Vitest workspace projects.
turbo.json Adds Turbo build pipelines for @devframes/plugin-git build + cli:build outputs.
tests/snapshots/tsnapi/@devframes/plugin-git/index.snapshot.js New public API snapshot for the plugin entry.
tests/snapshots/tsnapi/@devframes/plugin-git/index.snapshot.d.ts New public API type snapshot for the plugin entry.
pnpm-workspace.yaml Adds catalog deps for Radix UI, Tailwind v4 stack, Storybook React/Vite, etc.
plugins/git/tsdown.config.ts tsdown config for node-side entries (index, cli).
plugins/git/tsconfig.json Plugin TS config with explicit include/exclude (excluding Next client output dirs).
plugins/git/test/git.test.ts End-to-end RPC + snapshot dump tests for status/log/branches/diff and write actions.
plugins/git/test/_utils.ts Test utilities to boot an in-process HTTP+WS server + host context.
plugins/git/test/_repo.ts Test repo fixtures for deterministic git history/status/diffs.
plugins/git/src/rpc/index.ts Aggregates RPC function definitions and module augmentation for typed RPC.
plugins/git/src/rpc/functions/unstage.ts Implements git:unstage action (write mode only).
plugins/git/src/rpc/functions/status.ts Implements git:status query and porcelain-v2 parsing.
plugins/git/src/rpc/functions/stage.ts Implements git:stage action (write mode only).
plugins/git/src/rpc/functions/show.ts Implements git:show query + static dump behavior for commit details.
plugins/git/src/rpc/functions/log.ts Implements git:log query + static dump fallback page.
plugins/git/src/rpc/functions/diff.ts Implements git:diff query with optional per-file unified patch.
plugins/git/src/rpc/functions/commit.ts Implements git:commit action (write mode only) returning status + message.
plugins/git/src/rpc/functions/branches.ts Implements git:branches query for local branches + upstream tracking.
plugins/git/src/rpc/context.ts Per-context git configuration + memoized repo root resolution.
plugins/git/src/node/git.ts Node helpers to execute git commands, parse output, and format errors.
plugins/git/src/index.ts Defines createGitDevframe and exports the plugin’s public types.
plugins/git/src/client/tsconfig.json Next.js client TS config for the SPA.
plugins/git/src/client/postcss.config.mjs Tailwind v4 PostCSS config for the SPA.
plugins/git/src/client/next.config.mjs Next export config for portable static output (relative assets + trailingSlash).
plugins/git/src/client/lib/utils.ts cn() utility for class merging (clsx + tailwind-merge).
plugins/git/src/client/lib/refs.ts Parses git %D refs into structured labels for the commit graph.
plugins/git/src/client/lib/refs.test.ts Unit tests for parseRefs.
plugins/git/src/client/lib/commit-graph.ts Computes commit graph lane layout for the log view.
plugins/git/src/client/components/views/status-panel-view.tsx Status UI (staged/unstaged/untracked + optional commit UI).
plugins/git/src/client/components/views/status-panel-view.stories.tsx Storybook stories for Status panel UI.
plugins/git/src/client/components/views/log-panel-view.tsx Commit log UI with computed graph + infinite scroll sentinel.
plugins/git/src/client/components/views/log-panel-view.stories.tsx Storybook stories for Log panel UI.
plugins/git/src/client/components/views/diff-panel-view.tsx Diff list UI + patch renderer component.
plugins/git/src/client/components/views/diff-panel-view.stories.tsx Storybook stories for Diff panel UI.
plugins/git/src/client/components/views/commit-details-view.tsx Commit detail UI (metadata, changed files, patch when available).
plugins/git/src/client/components/views/commit-details-view.stories.tsx Storybook stories for Commit details UI.
plugins/git/src/client/components/views/branches-panel-view.tsx Branch list UI with upstream tracking indicators.
plugins/git/src/client/components/views/branches-panel-view.stories.tsx Storybook stories for Branches panel UI.
plugins/git/src/client/components/use-rpc-resource.ts Client hook for loading/refreshing RPC-backed resources.
plugins/git/src/client/components/ui/textarea.tsx shadcn/ui textarea component.
plugins/git/src/client/components/ui/tabs.tsx shadcn/ui tabs component (Radix).
plugins/git/src/client/components/ui/skeleton.tsx shadcn/ui skeleton component.
plugins/git/src/client/components/ui/separator.tsx shadcn/ui separator component (Radix).
plugins/git/src/client/components/ui/scroll-area.tsx shadcn/ui scroll area component (Radix).
plugins/git/src/client/components/ui/card.tsx shadcn/ui card component.
plugins/git/src/client/components/ui/button.tsx shadcn/ui button component (cva + Radix Slot).
plugins/git/src/client/components/ui/badge.tsx shadcn/ui badge component (cva + Radix Slot).
plugins/git/src/client/components/theme.ts Theme hook syncing .dark and localStorage.
plugins/git/src/client/components/status-panel.tsx Status container wiring RPC calls to Status view (including write actions).
plugins/git/src/client/components/rpc-provider.tsx Connects to devframe RPC and provides client context to the app.
plugins/git/src/client/components/log-panel.tsx Log container wiring pagination + status decoration into Log view.
plugins/git/src/client/components/diff-panel.tsx Diff container wiring scope toggle + per-file patch fetching.
plugins/git/src/client/components/dashboard.tsx Main dashboard layout (panes, branch selection, resizable rails).
plugins/git/src/client/components/commit-details-panel.tsx Commit details container wiring git:show to details view.
plugins/git/src/client/components/branches-panel.tsx Branches container wiring git:branches to branches view.
plugins/git/src/client/app/page.tsx Next App Router page mounting the dashboard.
plugins/git/src/client/app/layout.tsx Next root layout + inline theme bootstrap script.
plugins/git/src/client/app/globals.css Tailwind v4 theme + utilities and base styles for the dashboard.
plugins/git/src/cli.ts Standalone CLI entry using createCli(createGitDevframe()).
plugins/git/scripts/dev.mjs Dev script that runs devframe backend + Next dev server concurrently.
plugins/git/scripts/build-spa.mjs Copies Next export output into dist/client for packaging.
plugins/git/README.md Plugin documentation (install/CLI/programmatic usage + RPC surface).
plugins/git/package.json New publishable package manifest, scripts, deps, and bin entry.
plugins/git/LICENSE.md Plugin license file.
plugins/git/bin.mjs Bin shim that runs the compiled CLI entry.
plugins/git/.storybook/shims.d.ts Storybook TS shim for CSS imports in config.
plugins/git/.storybook/preview.tsx Storybook preview decorator for theme + global styles.
plugins/git/.storybook/main.ts Storybook config (React+Vite) with Tailwind plugin wiring.
plugins/git/.gitignore Ignores Next/build outputs for the plugin package.
plugins/code-server/tsconfig.json Updates code-server plugin TS config to explicit include/exclude.
plugins/code-server/package.json Adds typecheck script for the code-server plugin.
examples/next-runtime-snapshot/scripts/build-spa.mjs Factors SPA copy logic into a script (ensures dist/ exists).
examples/next-runtime-snapshot/package.json Uses the new build script instead of inline shell commands.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

}
}, [])

return <RpcContext value={state}>{children}</RpcContext>
Comment thread plugins/git/test/_repo.ts
Comment on lines +12 to +23
const GIT_ENV = {
...process.env,
GIT_AUTHOR_NAME: 'Test User',
GIT_AUTHOR_EMAIL: 'test@example.com',
GIT_COMMITTER_NAME: 'Test User',
GIT_COMMITTER_EMAIL: 'test@example.com',
GIT_AUTHOR_DATE: '2020-01-01T00:00:00Z',
GIT_COMMITTER_DATE: '2020-01-01T00:00:00Z',
// Ignore the developer's global/system config so commits are deterministic.
GIT_CONFIG_GLOBAL: '/dev/null',
GIT_CONFIG_SYSTEM: '/dev/null',
}
Comment on lines +47 to +51
<pre className="font-mono text-xs leading-relaxed">
{patch.split('\n').map((line, i) => (
<div key={i} className={cn('px-3 whitespace-pre', patchLineClass(line))}>{line || ' '}</div>
))}
</pre>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants